【React Native】 react-hook-form と yupを使ってフォームのバリデーションチェック
こんにちは、こんばんわ。 「クラスメソッドにジョインして、知識をいっぱい吸収出来て喜びを感じています」 CX 事業本部 Delivery 部 MAD グループ@札幌の hiro です。
今回も、前回の React Native 記事に味を占めて、React Native 連投します。
はじめに
React Native でネイティブアプリを作成し、フォーム画面を作った時にフォームのバリデーション処理を入れなければ、 と思ったときにやった内容を記述します。 フォームのバリデーション処理は、 Formikなどもありますが、
今回は、 react-hook-formとyupを 組み合わせてバリデーション処理を実施していきました。
内容
React Native の環境は良しなに、作成よろしくお願いいたします! 以下記事など参考にしつつ、React Native for Webを利用して環境を構築しました。 大変参考になるので、一読を!
https://dev.classmethod.jp/articles/react-native-for-web-with-typescript-while-referring-to-the-official-introduction/
ライブラリのインストール
今回必要になるライブラリのインストールをします。
- React Hook Form
yarn add react-hook-form
- yup
yarn add yup
動作確認
以下のように、条件を入力するとバリデーションチェックをしてくれるようになっています。
フォーム部分
今回は、ログインフォームのバリデーション処理を加える前提で記述します。
◇ ファイル構成
以下のファイル構成で、記述します。
src ┗ App.tsx・・・・・・・・ログインなどをする際のフォーム画面の表示 ┣ component/ ┃ ┗ TestInputComponent.tsx・・・フォーム入力部分の表示 ┗ schema/ ┗ testInputSchema.ts・・・・・バリデーション処理管理部分
◇ フォーム画面部分
簡単にログイン画面表示部分を以下のように記述しています。 hudleSumitが実行されることでバリデーションチェック処理が走ります。
ここで使用されている「react-hook-form」の「Control」や「useForm」などは、 以下のリンクにより詳細に記述されています。
以下が実際のファイル内容になります。
import React from "react"; import { View, Text, StyleSheet, Pressable } from "react-native"; import { useForm, Control, FieldValues, SubmitHandler, SubmitErrorHandler } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import { TestInputComponent } from "./component/TestInputComponent"; import { testInputSchema } from "./schema/testInputSchema"; type FormDataInfo = { email: string; password: string; }; export const App = () => { const { control, handleSubmit } = useForm<FormDataInfo>({ resolver: yupResolver(testInputSchema), }); const onSubmit: SubmitHandler<FormDataInfo> = (data: any, e: any) => console.log(data, e); const onError: SubmitErrorHandler<FormDataInfo> = (errors: any, e: any) => console.log(errors, e); return ( <View style={styles.container}> <TestInputComponent control={control as unknown as Control<FieldValues>} areaName="email" label="メールアドレス" placeholder="メールアドレス" autoCompleteType="email" autoCapitalize="none" style={styles.input} /> <TestInputComponent control={control as unknown as Control<FieldValues>} areaName="password" label="パスワード" placeholder="パスワード" autoCompleteType="password" secureTextEntry style={styles.input} /> <Pressable style={styles.button} onPress={() => handleSubmit(onSubmit, onError)()} > <Text style={styles.text}>BUTTON</Text> </Pressable> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, marginHorizontal: 100, paddingTop: 22, }, input: { shadowOpacity: 0.5, shadowRadius: 3, shadowOffset: { height: 0, width: 0, }, elevation: 2, marginTop: 30, paddingVertical: 20, paddingHorizontal: 20, }, button: { marginTop: 30, paddingVertical: 20, alignItems: "center", justifyContent: "center", paddingHorizontal: 32, borderRadius: 4, elevation: 3, backgroundColor: "blue", }, text: { fontSize: 16, lineHeight: 21, fontWeight: "bold", letterSpacing: 0.25, color: "white", }, }); export default App;
◇ フォーム入力部分
次にフォーム入力表示部分を以下のように記述しています。 入力された値を参考に、バリデーションエラーが発生した際の状況などを表示するようにしています。
以下が実際のファイル内容になります。
import React from "react"; import { TextInput, TextInputProps, Text, View, StyleSheet, } from "react-native"; import { Controller, Control, DeepMap, FieldValues, FieldError, } from "react-hook-form"; interface Props extends TextInputProps { control: Control<any>; areaName: string; defaultValue?: any; label: string; autoCompleteType: string; } export const TestInputComponent: React.FC<Props> = ({ control, areaName, defaultValue, ...props }) => { return ( <Controller control={control} name={areaName} defaultValue={defaultValue} render={({ field: { onChange, value, onBlur, name }, formState: { errors }, }) => ( <View> <TextInput // このpropsにautoCompleteTypeなど諸々乗っかってくる {...props} value={value || ""} onBlur={onBlur} onChangeText={onChange} /> {/* バリエーションエラー表示 */} {errors[name] && ( <Text style={styles.text}> {(errors[name] as DeepMap<FieldValues, FieldError>)?.message} </Text> )} </View> )} /> ); }; const styles = StyleSheet.create({ text: { color: "red", }, });
◇ バリデーション処理部分
次にバリデーション処理部分を以下のように記述しています。 よくあるバリデーションの内容もコメントアウトして記述しています。 パスワードが一致しないことなどなど。
yup.object()と.shape()は以下のような感じです。
- yup.object() バリデーション判定対象の入力値が、オブジェクトで提供されることを期待する定義 - .shape() バリデーションしたいデータ構造を.shape()で定義
以下が実際のファイル内容になります。
import * as yup from "yup"; // スキーマを定義 // inputのvalue値のエラー条件を定義 export const testInputSchema = yup.object().shape({ email: yup .string() .lowercase() .email("正しいメールアドレスを入力してください。") .required("メールアドレスは必須項目です。"), password: yup .string() .matches(/(?=.*[a-z])/, "小文字を含めてください。") .matches(/(?=.*[A-Z])/, "大文字を含めてください。") .matches(/(?=.*[0-9])/, "数字を含めてください。") .min(8, "最低8文字含めてください。") .required("パスワードは必須項目です。"), /** * よくある他のバリデーションチェック例 */ // メールアドレス確認用の入力をチェックする用 //checkEmail: yup // .string() // .lowercase() // .email('正しいメールアドレスを入力してください。') // .test('emails-match', '入力されたメールアドレスが一致しません。', function (value) { // return value === this.parent.email; // }) // .required('メールアドレス確認は必須項目です。'), // かな入力をチェックする用 // nameKana: yup // .string() // .max(25, '最大25文字です。') // .test('katakana-checker', 'カタカナで入力して下さい。', function (value: any) { // return !!value.match(/^[ァ-ヶー ]*$/); // }) // .required('氏名(カナ)は必須項目です。'), });
おわりに
バリデーションチェックのライブラリはいくつかありますが、今回は react-hook-formとyupを選択して、組み合わせた内容を記述しました。
ありがとうございました。